package com.declum.peyar;

import java.net.InetSocketAddress;
import java.nio.charset.Charset;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.GnuParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.apache.mina.common.ByteBuffer;
import org.apache.mina.common.IoAcceptor;
import org.apache.mina.common.IoSession;
import org.apache.mina.common.SimpleByteBufferAllocator;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.transport.socket.nio.SocketAcceptor;
import org.apache.mina.transport.socket.nio.SocketAcceptorConfig;

import com.declum.peyar.handler.PeyarHandler;

/**
 * PeyarServer that encapsulate the Peyar Handler with a Socket
 * 
 * @author clement
 * 
 */
public class PeyarServer {
	private static Logger logger;
	private static int port = 12345;
	private static IoAcceptor acceptor;
	private static InetSocketAddress inetSocketAddress;

	public static void main(String[] args) throws Exception {
		/**
		 * Configure the Logger object
		 */
		PropertyConfigurator.configure("log4jconfig.prp");

		/**
		 * Initialize the Logger
		 */
		PeyarServer.logger = Logger.getLogger(PeyarServer.class);

		CommandLineParser parser = new GnuParser();

		Options opts = new Options();
		opts.addOption("d", "dir", true, "Specify working directory");
		opts.addOption("p", "port", true,
				"Port number at which the server has to listen");
		CommandLine line = null;

		try {
			line = parser.parse(opts, args);
		} catch (ParseException exp) {
			System.err.println("Parsing failed.  Reason: " + exp.getMessage());
		}
		String workingDirectory = null;

		if (line == null) {
			System.exit(-1);
			return;
		}
		workingDirectory = line.getOptionValue("d");
		if (workingDirectory == null) {
			PeyarServer.printUsage(opts);
			System.exit(0);
			return;
		}
		String portStr = line.getOptionValue("p");
		if (portStr != null) {
			try {
				PeyarServer.port = Integer.parseInt(portStr);
			} catch (Exception e) {
				PeyarServer.logger.debug("Port number format is error");
			}
		}

		/**
		 * Was not knowing why this is for
		 */
		ByteBuffer.setUseDirectBuffers(false);

		/**
		 * I think for Heap Allocation
		 */
		ByteBuffer.setAllocator(new SimpleByteBufferAllocator());

		PeyarServer.acceptor = new SocketAcceptor();

		/**
		 * Create a SocketAccepterConfig to configure the Server Socket
		 */
		SocketAcceptorConfig cfg = new SocketAcceptorConfig();

		/**
		 * Add a logger hander in the Chain
		 */
		// cfg.getFilterChain().addLast("logger", new LoggingFilter());

		/**
		 * Add the Text decoder/encoder to the chain, this processes the request
		 * and call PeyarHandler handler for each line
		 */
		cfg.getFilterChain().addLast(
				"codec",
				new ProtocolCodecFilter(new TextLineCodecFactory(Charset
						.forName("UTF-8"))));

		/**
		 * This is our Custom Handler for the Service
		 */
		PeyarHandler peyarHandler = new PeyarHandler();

		/**
		 * Bind the Server to a port
		 */
		try {
			PeyarServer.inetSocketAddress = new InetSocketAddress(
					PeyarServer.port);
			PeyarServer.acceptor.bind(PeyarServer.inetSocketAddress,
					peyarHandler, cfg);
			PeyarServer.logger
					.debug("Declum Peyar server (Naming Service) started. Listening at "
							+ PeyarServer.port);
		} catch (Exception e) {
			PeyarServer.logger.error(e);
		}

	}

	public static void stopServer() {
		if (PeyarServer.acceptor != null) {
			PeyarServer.acceptor.unbind(PeyarServer.inetSocketAddress);
			for (IoSession session : PeyarServer.acceptor
					.getManagedSessions(PeyarServer.inetSocketAddress)) {
				if (session.isConnected() && !session.isClosing()) {
					session.close();
				}
			}
			PeyarServer.acceptor.unbindAll();

		}
		PeyarServer.logger.debug("Peyar Server stopped");

	}

	private static void printUsage(Options opts) {
		HelpFormatter formatter = new HelpFormatter();
		formatter.printHelp("PeyarServer", opts);
	}
}
